Ruby 原生有個 module 很好用,只要 include 他,你就可以自行定義大小比較的規則,在你的世界,誰大誰小你說了算!
這個 module 叫做 Comparable
。
在 include 他之後,你需要定義你的實體方法 <=>
來控制大小比對的結果。回傳 -1
代表小於,0
代表相等,1
代表大於。
這可以應用在像是權限判斷或是狀態更新的控制。
這邊以權限判斷為例,假設有三種權限由小到大分別是 訪客、使用者、VIP、管理員
class Role < String # 因為本質是一種字串資料,因此繼承字串
include Comparable
AVAILABLES = %w(passenger user vip admin).freeze
def <=>(another)
# 這邊範例使用表示權限的字串在 AVAILABLES 裡的位置來進行比對,越後面越大,越前面越小,找不到的最小
index = AVAILABLES.index(self) || 0
another_index = AVAILABLES.index(another.to_s) || 0
index <=> another_index
end
end
接著我們來測試看看他是否能如筆者所說般進行大小比對。
passenger = Role.new 'passenger'
user = Role.new 'user'
vip = Role.new 'vip'
admin = Role.new 'admin'
admin > passenger # true
passenger > vip # false
vip > user # true
user > admin # false
看起來是完全照預想中運作的!
那麼只要把他帶入 model 的權限欄位像是 user.role
就可以暗渡陳倉,讓這個欄位多出這樣一個比對的功能了!
class User < ApplicationRecord
def role
Role.new self[:role]
end
end
user = User.first
user.role # 假設是 "user"
user.role.class
=> Role # 可以看到其實已經變成是 Role 了
user.role > :admin
=> false
user.role < :admin
=> true # 成功!
其實在 Rails 的 String 本身就已經幫你裝好了這 module,就沒必要額外再 include了。
而且還不只如此,Rails 有內建一個 class ActiveSupport::StringInquirer
是繼承自 String 的,他更多了個特異功能,只要對他使用 .something?
任何以問號結尾的 method,就會回傳 self == "something"
的結果,相當帥氣。
class Role < ActiveSupport::StringInquirer # 改為繼承自 StringInquirer
# 其餘一切設定如上
end
# model 設定也如上,此處省略
user = User.first
user.role < :admin
=> true
user.role.user?
=> true
user.role.admin?
=> false
這樣一來,是不是就能讓你的 code 更簡潔易讀了呢?